package org.spring.aop.aspectj;

import lombok.NoArgsConstructor;
import org.aspectj.weaver.tools.PointcutExpression;
import org.aspectj.weaver.tools.PointcutParser;
import org.aspectj.weaver.tools.PointcutPrimitive;
import org.spring.aop.ClassFilter;
import org.spring.aop.MethodMatcher;
import org.spring.aop.Pointcut;
import org.spring.aop.support.AbstractExpressionPointcut;
import org.tool.reflect.ClassLoaderUtil;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

/**
 * Spring {@link Pointcut} 实现，它使用 AspectJ 编织器来评估切入点表达式。
 * <p>
 * 切入点表达式值是一个 AspectJ 表达式。这可以引用其他切入点并使用组合和其他操作。
 * <p>
 * 当然，由于这是由 Spring AOP 的基于代理的模型处理的，因此只支持方法执行切入点。
 *
 * @author 李坤
 * @date 2022/4/17 23:07
 */
@NoArgsConstructor
public class AspectJExpressionPointcut extends AbstractExpressionPointcut implements Pointcut, ClassFilter, MethodMatcher {

    /**
     * 支持的切入点表达式集合
     */
    private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<>();

    static {
        SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
        SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION);
    }

    /**
     * 切入点表达式
     */
    private String expression;

    /**
     * 切人点表达式
     */
    private PointcutExpression pointcutExpression;

    /**
     * 默认构造函数据
     *
     * @param expression 切入点表达式
     */
    public AspectJExpressionPointcut(String expression) {
        this.setExpression(expression);
        PointcutParser pointcutParser = this.initializePointcutParser();
        this.pointcutExpression = pointcutParser.parsePointcutExpression(expression);
    }


    @Override
    public ClassFilter getClassFilter() {
        return this;
    }

    @Override
    public MethodMatcher getMethodMatcher() {
        return this;
    }


    @Override
    public boolean matches(Class<?> clazz) {
        return pointcutExpression.couldMatchJoinPointsInType(clazz);
    }


    @Override
    public boolean isRuntime() {
        return true;
    }

    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        return pointcutExpression.matchesMethodExecution(method).alwaysMatches();
    }

    @Override
    public boolean matches(Method method, Class<?> targetClass, Object... args) {
        return true;
    }

    /*--------------------------------------------------private methods-----------------------------------------------*/

    /**
     * 初始化 PointcutParser 对象
     *
     * @return PointcutParser 对象
     */
    private PointcutParser initializePointcutParser() {
        // 获取默认的 ClassLoader 对象
        ClassLoader classLoader = ClassLoaderUtil.getDefaultClassLoader();
        return PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, classLoader);
    }

}
